"""
================================================================================

    abc2esac - ABC to EsAC conversion
    Copyright (C) 2010, Marcus Weseloh

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

================================================================================
"""

import os
import tempfile
from fractions import Fraction as F
from subprocess import Popen, PIPE

from abcesac.music import Note, Rest

class TemperleyGrouper(object):
    """Segment a list of notes into phrases using the Temperley grouper
    algorithm"""
    def __init__(self, meter_cmd=None, grouper_cmd=None, grouper_params=None):
        self.ticks_per_128th = 18.75 
        self.meter_cmd = meter_cmd or 'meter'
        self.grouper_cmd = grouper_cmd or 'grouper'
        self.grouper_params = grouper_params

    def group(self, song):
        """Takes a song instance and return a list of note indices that
        represent phrase endings"""
        note_list = self.get_note_list(song)
        notefile = tempfile.NamedTemporaryFile(delete=False)
        notefile.write(note_list)
        notefile.close()

        cmd = ' '.join([self.meter_cmd, notefile.name])
        proc = Popen(cmd, shell=True, stdout=PIPE)
        beatnote_list = proc.communicate()[0]

        beatnotefile = tempfile.NamedTemporaryFile(delete=False)
        beatnotefile.write(beatnote_list)
        beatnotefile.close()

        cmd = [self.grouper_cmd]
        if self.grouper_params:
            cmd.extend(['-p', self.grouper_params])
        cmd.append(beatnotefile.name)
        proc = Popen(' '.join(cmd), shell=True, stdout=PIPE)
        output = proc.communicate()[0]

        os.unlink(notefile.name)
        os.unlink(beatnotefile.name)

        i = 0
        phrase_endings = []
        for line in output.split('\n'):
            if line.startswith('Phrase'):
                phrase_endings.append(i)
            else:
                i += 1
        return phrase_endings

    def get_note_list(self, song):
        """Turn elements into a note list as expected by meter and grouper
        programs"""
        ontime = 0
        note_list = []

        for bar in song.bars:
            for el in bar.note_list():
                if isinstance(el, Note):
                    duration = int((el.get_total_length() / F(1, 128)) *
                                   self.ticks_per_128th)
                    offtime = ontime + duration
                    note_list.append(['Note', ontime, offtime,
                                      el.get_midi_pitch()])
                    ontime = offtime
                elif isinstance(el, Rest):
                    duration = int((el.get_total_length() / F(1, 128)) *
                                   self.ticks_per_128th)
                    ontime += duration
        return '\n'.join([' '.join(map(str, n)) for n in note_list])
